# -*- coding: utf-8 -*-
"""
本地文件ｃａｃｈｅ
"""
from __future__ import print_function, unicode_literals
import pickle
import os
import atexit


class MemoryCache(object):

    def __init__(self, fun=None):
        """
        初始化
        :param fun:
        """
        self.fun = fun
        self.dict = {}

    def get(self, key):
        """
        获取数据
        :param key:
        :return:
        """
        if key not in self.dict:
            self.dict[key] = self.fun(*key)
        return self.dict[key]

    def __call__(self, fun):
        """
        装饰器
        :param fun:
        :return:
        """
        self.fun = fun
        def wrap_fun(*args):
            return self.get(args)
        return wrap_fun


class CacheWithFile(object):

    def __init__(self, fun=None, path_base='', mem_n=0):
        self.dir_path = path_base + '.cache.dir'
        self.cache_path = path_base + '.cache.detail'
        self.fun = fun
        self.changed = False

        self.dir = {}
        if os.path.exists(self.dir_path):
            with open(self.dir_path, 'rb') as f:
                data = f.read()
                if data:
                    self.dir = pickle.loads(data)

        if not os.path.exists(self.cache_path):
            f = open(self.cache_path, 'w+')
            f.close()
        self.cache_file = open(self.cache_path, 'a+')

        self.mem_cache = {}
        self.mem_n = mem_n
        if mem_n > 0:
            self.get = self.get_mem
        else:
            self.get = self.get_file

        atexit.register(self.save)

    def save(self):
        if self.changed:
            with open(self.dir_path, 'wb') as f:
                pickle.dump(self.dir, f)

    def get_mem(self, key):
        ret = self.mem_cache.get(key)
        if ret:
            return ret

        pos, size = self.dir.get(key, (None, None))
        if pos is None:
            ret = self.fun(*key)
            self.put(key, ret)
            return ret

        else:
            self.cache_file.seek(pos)
            v = self.cache_file.read(size)
            ret = eval(v)
            if len(self.mem_cache) < self.mem_n:
                self.mem_cache[key] = ret
            return ret

    def get_file(self, key):
        pos, size = self.dir.get(key, (None, None))
        if pos is None:
            ret = self.fun(*key)
            self.put(key, ret)
            return ret
        else:
            self.cache_file.seek(pos)
            v = self.cache_file.read(size)
            return eval(v)

    def put(self, key, value):
        self.cache_file.seek(0, os.SEEK_END)
        pos = self.cache_file.tell()
        self.cache_file.write(repr(value))
        size = self.cache_file.tell() - pos
        self.dir[key] = (pos, size)
        self.changed = True

    def __call__(self, fun):
        """
                装饰器
                :param fun:
                :return:
                """
        self.fun = fun

        def wrap_fun(*args):
            return self.get(args)

        return wrap_fun


class FileCache(object):
    """
    文件缓存
    """
    def __init__(self, path=None, max_num=None):
        self.path = path
        self.dict = {}
        self.key_pos = {}

    def get(self, key):
        """
        获取数据
        :param key:
        :return:
        """
        if key not in self.dict:
            if key not in self.all:
                self.dict[key] = self.fun(*key)
                self.all.add(Key)


        return self.dict[key]



